package com.authine.cloudpivot.web.api.helper;

import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.engine.api.model.bizmodel.BizPropertyModel;
import com.authine.cloudpivot.engine.api.model.bizmodel.BizSchemaModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizCommentModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizObjectModel;
import com.authine.cloudpivot.engine.api.model.runtime.WorkItemModel;
import com.authine.cloudpivot.engine.enums.ErrCode;
import com.authine.cloudpivot.engine.enums.status.SequenceStatus;
import com.authine.cloudpivot.engine.enums.type.BizPropertyType;
import com.authine.cloudpivot.engine.enums.type.FormActionType;
import com.authine.cloudpivot.engine.enums.type.OperationType;
import com.authine.cloudpivot.engine.workflow.model.WorkflowTemplateHeader;
import com.authine.cloudpivot.engine.workflow.model.activity.ParticipantActivity;
import com.authine.cloudpivot.engine.workflow.model.data.PropertyPermission;
import com.authine.cloudpivot.web.api.controller.base.RuntimeController;
import com.authine.cloudpivot.web.api.dubbo.DubboConfigService;
import com.authine.cloudpivot.web.api.exception.PortalException;
import com.authine.cloudpivot.web.api.util.ClientUtils;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.authine.cloudpivot.web.api.view.runtime.WorkItemSubmitVO;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class FormSubmitHelper extends RuntimeController {

    @Value("${cloudpivot.api.comment.optimized:false}")
    private boolean commentOptimized = false;
    @Autowired
    public DubboConfigService dubboConfigService;
    @Autowired
    public HttpServletRequest request;

    public ResponseResult<Map<String, Object>> submit(WorkItemSubmitVO workItemSubmit, String userId, String schemaCode) {
        String formType = workItemSubmit.getFormType();
        if (log.isDebugEnabled()) {
            log.debug("提交表单操作, formType = {}.", formType);
        }
        if (StringUtils.isEmpty(formType)) {
            throw new PortalException(ErrCode.SYS_PARAMETER_ERROR, "formType 为空");
        }else{
            long start = System.currentTimeMillis();
            BizObjectHelper bizObjectHelper = new BizObjectHelper(this.getWorkflowInstanceFacade(), this.getBizObjectFacade(), this.getOrganizationFacade(), dubboConfigService);
            BizObjectHelper.BizObjectContext bizObjectContext = bizObjectHelper.initSubmitBizObject(workItemSubmit, userId);
            String ownerId = bizObjectContext.getOwner();
            log.info("initSubmitBizObject cost : {}", System.currentTimeMillis() - start);
            log.info("initSubmitBizObject cost : {}", System.currentTimeMillis() - start);
            if (!bizObjectContext.isWfIsSubmit()) {
                this.getWorkflowInstanceFacade().handleBeforeSubmit(bizObjectContext.getBizObject());
            }

            log.info("handleBeforeSubmit cost : {}", System.currentTimeMillis() - start);
            Map<String, Object> map = Maps.newHashMap();
            byte var11 = -1;
            switch(formType.hashCode()) {
                case 49:
                    if (formType.equals("1")) {
                        var11 = 1;
                    }
                    break;
                case 50:
                    if (formType.equals("2")) {
                        var11 = 0;
                    }
            }
            switch(var11) {
                case 0:
                    map = this.submitBizSheet(userId, workItemSubmit.getBizObject());
                    log.info("submitBizSheet cost time total: {}", System.currentTimeMillis() - start);
                    return this.getOkResponseResult(map, "数据保存成功");
                case 1:
                    WorkItemModel workItem = null;
                    if (StringUtils.isNotEmpty(workItemSubmit.getWorkItemId())) {
                        workItem = this.getWorkflowInstanceFacade().getWorkItem(workItemSubmit.getWorkItemId());
                        if (workItem == null) {
                            return this.getErrResponseResult(map, ErrCode.WORKFLOW_WORK_ITEM_EMPTY.getErrCode(), "当前任务已被取消或者已被处理");
                        }
                    }

                    log.info("getWorkItem cost : {}", System.currentTimeMillis() - start);
                    if (StringUtils.isNotEmpty(workItemSubmit.getWorkflowInstanceId()) && StringUtils.isNotEmpty(workItemSubmit.getWorkItemId())) {
                        map = this.submitWorkflowByInstanceIdAndItemId(userId, ownerId, workItemSubmit, workItem,schemaCode);
                        return this.getOkResponseResult(map, "任务提交成功");
                    } else if (StringUtils.isNotEmpty(workItemSubmit.getWorkflowCode())) {
                        map = this.submitWorkflowByWorkflowCode(userId, ownerId, workItemSubmit);
                        return this.getOkResponseResult(map, "任务提交成功");
                    } else if (StringUtils.isEmpty(workItemSubmit.getWorkflowInstanceId()) || StringUtils.isEmpty(workItemSubmit.getWorkItemId()) || StringUtils.isNotEmpty(workItemSubmit.getWorkflowCode())) {
                        throw new PortalException(ErrCode.SYS_PARAMETER_EMPTY, "提交任务的参数workflowInstanceId、workItemId或workflowCode为空");
                    } else {
                        log.info("submit workflow sheet. cost time total: {}", System.currentTimeMillis() - start);
                    }
                default:
                    throw new PortalException(ErrCode.UNKNOW_ERROR, "未知错误.");
            }

        }
    }


    /**
     * 流程编码不为空时，提交流程表单
     * <p>
     * 1. finalCommentsSize > 1
     * 过滤出可写的审批数据项数量存在两个以上时，属于表单设计问题，要抛异常
     * 2. finalCommentsSize == 1
     * 保存审批意见数据
     * 3. finalCommentsSize == 0
     * 保存默认的审批意见数据
     *
     * @param userId              用户id
     * @param workItemSubmit      数据对象
     * @return Map
     */

    protected Map<String, Object> submitWorkflowByWorkflowCode(String userId, String ownerId, WorkItemSubmitVO workItemSubmit) {
        BizObjectModel bizObjectModel = workItemSubmit.getBizObject();
        //final String objectId = saveBizObject(userId, workItemSubmit.getBizObject());
        String objectId = bizObjectModel.getId();
        final String workflowInstanceId = startWorkflow(workItemSubmit.getDepatmentId(), userId, bizObjectModel, workItemSubmit.getApproval(), workItemSubmit.getWorkflowCode(), Boolean.TRUE);

        Map<String, Object> map = Maps.newHashMap();
        map.put("objectId", objectId);
        map.put("workflowInstanceId", workflowInstanceId);
        map.put("result", true);

        //BizObjectCreatedModel bizObjectCreated = getBizObjectFacade().getBizObject(userId, bizObjectModel.getSchemaCode(), objectId);
        //writeOperationLogForBizObject(workflowInstanceId, null, null, OperationType.UPDATE_BIZ_OBJECT, bizObjectCreated);
        //writeOperationLog(workflowInstanceId, workItemSubmit.getWorkItemId(), null, OperationType.SUBMIT, null);
        return map;
    }

    /**
     * 发起流程，并返回流程实例id
     *
     * @param depatmentId  部门id
     * @param userId       用户id
     * @param objectModel  业务对象id
     * @param workflowCode 流程编码
     * @param finishStart  是否结束发起节点
     * @return 当前任务对象
     */

    protected String startWorkflow(String depatmentId, String userId, BizObjectModel objectModel, BizCommentModel bizCommentModel, String workflowCode, Boolean finishStart) {
        //String workflowInstanceId = getWorkflowInstanceFacade().startWorkflowInstance(depatmentId, userId, workflowCode, objectId, finishStart);

        long start = System.currentTimeMillis();
        final String client = ClientUtils.getClient(request);
        final String clientIP = ClientUtils.getClientIP(request);
        String workflowInstanceId = getWorkflowInstanceFacade().startWorkflowInstance(depatmentId, userId, null,workflowCode, objectModel, bizCommentModel, clientIP, client, finishStart);
        log.info("流程启动成功，workflowInstanceId = {}, 调用引擎接口耗时：{}ms", workflowInstanceId, (System.currentTimeMillis() - start));
        return workflowInstanceId;
    }


    /**
     * 获取审批意见数据项编码
     * @param comments  审批意见
     * @param propertyPermissions 数据项
     * @return 审批意见数据项编码
     */

    protected List<String> getCommentCodes(Map<String, Object> comments, List<PropertyPermission> propertyPermissions) {
        List<String> propertyPermissionsCode = Lists.newArrayList();
        List<String> finalCommentCodes = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(propertyPermissions)) {
            // 过滤出流程设计中设置的可写数据项的编码集合
            propertyPermissionsCode = propertyPermissions.stream().filter(PropertyPermission::isEditable).map(PropertyPermission::getPropertyCode).collect(Collectors.toList());
        }

        if (log.isTraceEnabled()) {
            log.trace("允许可写的数据项 propertyPermissionsCode = {}", JSONObject.toJSONString(propertyPermissionsCode));
            log.trace("执行getCommentsAndRemoveComments后 comments = {}", JSONObject.toJSONString(comments));
        }
        if (MapUtils.isNotEmpty(comments)) {
            for(String commentCode : comments.keySet()) {
                if (propertyPermissionsCode.contains(commentCode)) {
                    // 计算待更新的审批意见数据项个数
                    finalCommentCodes.add(commentCode);
                }
            }
        }
        return finalCommentCodes;
    }


    /**
     * 获取审批意见并移除意见
     *
     * @param workflowCode 流程编码
     * @param data         表单数据
     * @return Map
     */

    protected Map<String, Object> getCommentsAndRemoveComments(String workflowCode, String schemaCode, Map<String, Object> data) {
        if (data == null) {
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug("workflowCode = {}, schemaCode = {}", workflowCode, schemaCode);
        }
        if (StringUtils.isNotEmpty(workflowCode)) {
            WorkflowTemplateHeader header = getAppManagementFacade().getWorkflowTemplateHeader(workflowCode);
            schemaCode = header.getSchemaCode();
        }

        BizSchemaModel bizSchemaModel = getAppManagementFacade().getBizSchemaBySchemaCode(schemaCode, Boolean.TRUE);
        if (bizSchemaModel == null) {
            return null;
        }
        // 过滤出审批意见数据项
        List<BizPropertyModel> propertyModels = bizSchemaModel.getProperties().stream().filter(m -> m.getPropertyType() == BizPropertyType.COMMENT && m.getPublished()).collect(Collectors.toList());

        List<String> commentCode = propertyModels.stream().map(BizPropertyModel::getCode).collect(Collectors.toList());
        if (log.isTraceEnabled()) {
            log.trace("审批意见数据项:{}", JSONObject.toJSONString(propertyModels));
            log.trace("审批意见数据项编码:{}", JSONObject.toJSONString(commentCode));
        }

        Map<String, Object> commentMap = org.apache.curator.shaded.com.google.common.collect.Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(commentCode)) {
            for (String code : commentCode) {
                commentMap.put(code, data.get(code) == null ? org.apache.curator.shaded.com.google.common.collect.Maps.newHashMap() : data.get(code));
                if (log.isDebugEnabled()) {
                    log.debug("删除审批意见.. code = {}", code);
                }
                data.remove(code);
            }
        }
        if (log.isTraceEnabled()) {
            log.trace("意见结果, commentMap = {}...", JSONObject.toJSONString(commentMap));
            log.trace("data = {}", JSONObject.toJSONString(data));
        }
        return commentMap;
    }


    /**
     * 实例Id和任务Id不为空时，提交流程表单
     * <p>
     * 保存时，分开bizObject的审批意见和非审批意见数据后，分开保存
     * 1. finalCommentsSize > 1
     * 过滤出可写的审批数据项数量存在两个以上时，属于表单设计问题，要抛异常
     * 2. finalCommentsSize == 1
     * 保存审批意见数据
     * 3. finalCommentsSize == 0
     * 保存默认的审批意见数据
     *
     * @param userId              用户id
     * @param workItemSubmit      数据对象
     * @return Map
     */

    protected Map<String, Object> submitWorkflowByInstanceIdAndItemId(String userId, String ownerId, WorkItemSubmitVO workItemSubmit, WorkItemModel workItem,String schemaCode) {
        long start = System.currentTimeMillis();
        String activityCode = workItem != null ? workItem.getActivityCode() : null;
        ParticipantActivity participantActivity = this.getParticipantActivity(workItemSubmit.getWorkflowCode(), workItemSubmit.getWorkflowInstanceId(), activityCode);
        if (participantActivity != null) {
            workItemSubmit.getBizObject().setFormCode(participantActivity.getSheetCode());
        }
        log.info("setFormCode cost : {}", System.currentTimeMillis() - start);
        workItemSubmit.getBizObject().setWorkflowInstanceId(workItemSubmit.getWorkflowInstanceId());
        String objectId = this.saveBizObject(userId, workItemSubmit.getBizObject());
        log.info("saveBizObject cost : {}", System.currentTimeMillis() - start);
        Boolean result = getWorkflowInstanceFacade().submitWorkItem(ownerId, workItemSubmit.getWorkItemId(), workItemSubmit.getAgree());
        log.info("submitWorkItem cost : {}", System.currentTimeMillis() - start);
        if (result || !workItemSubmit.getAgree()) {
            this.saveComment(userId, objectId,schemaCode, new BizCommentModel(), workItemSubmit.getAgree() ? FormActionType.AGREE : FormActionType.DIS_AGREE);
            if (log.isDebugEnabled()) {
                log.debug("提交流程表单submitWorkflowByInstanceIdAndItemId，objId = {}", objectId);
            }
        }
        log.info("saveComment cost : {}", System.currentTimeMillis() - start);
        Map<String, Object> map = Maps.newHashMap();
        map.put("result", result);
        map.put("objectId", objectId);
        this.writeOperationLog(workItemSubmit.getWorkflowInstanceId(), workItemSubmit.getWorkItemId(), (String)null, OperationType.SUBMIT,null);
        return map;
    }



    /**
     * 提交业务表单.
     *
     * @param userId         用户id
     * @param bizObjectModel 数据对象
     */

    private Map<String, Object> submitBizSheet(String userId, BizObjectModel bizObjectModel) {
        // 业务表单提交时过滤掉审批意见数据项
        final String schemaCode = bizObjectModel.getSchemaCode();
        final String formCode = bizObjectModel.getFormCode();
        bizObjectModel.setSequenceStatus(SequenceStatus.COMPLETED.toString());
        final String objectId = this.saveBizObject(userId, bizObjectModel);

        final Map<String, Object> map = Maps.newHashMap();
        map.put("objectId", objectId);
        map.put("schemaCode", schemaCode);
        map.put("formCode", formCode);
        return map;
    }
}